1. РАБОТА С ТАЙМЕРАМИ

Класс javax.swing.Timer является таймером подсистемы Swing, используется в программах с графическим интерфейсом для периодического выполнения задачи (набора команд) с заранее заданным интервалом.

Класс java.util.Timer является таймером общего назначения, используется в программах без графического интерфейса или при необходимости долгой обработки данных, а также для выполнения фоновых задач по расписанию в отдельном потоке.

У таймеров Swing имеется событие «actionPerformed», которое вызывается при срабатывании таймера, а также методы:

         setRepeats(false) – установка режима единичного срабатывания таймера;

         start  - запуск таймера;

         stop – остановка таймера.

Таймеры общего назначения используют класс задания «java.util.TimerTask», в методе «run» которого реализуется код таймера. Запускаются таймеры общего назначения методом «schedule».

1.1. Пример работы с swing-таймерами

public class Form1 extends javax.swing.JFrame {

// Текст таймера прописывается в данном месте кода формы вручную!

// Таймер будет вызываться каждую миллисекунду

javax.swing.Timer jTimer1 = new javax.swing.Timer(1, new ActionListener() {

public void actionPerformed(ActionEvent evt) { // МЕТОД ТАЙМЕРА 1

Point p = jLabel1.getLocation();

if (p.x <= 300) { ++p.x; } else { jTimer1.stop();jTimer2.start(); }

jLabel1.setLocation(p);

}

});

// Текст таймера прописывается в данном месте кода формы вручную!

// Таймер будет вызываться каждую миллисекунду

javax.swing.Timer jTimer2 = new javax.swing.Timer(1, new ActionListener() {

public void actionPerformed(ActionEvent evt) { // МЕТОД ТАЙМЕРА 2

Point p = jLabel1.getLocation();

if (p.x >= 30) { --p.x; } else { jTimer2.stop();jTimer1.start(); }

jLabel1.setLocation(p);

}

});

public Form1() {

initComponents();

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {

// Запуск таймера

jTimer1.start();

}

private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {

// Остановка  таймеров

jTimer1.stop();  jTimer2.stop();

}

1.2. Пример работы с таймером общего назначения

public Form1() { // ----------- Вписывается в конструктор формы после вызова «initComponents()»

initComponents();

// Текст таймера прописывается в данном месте кода формы вручную!

// Таймер запускается с задержкой «0» миллисекунд, и будет вызываться раз в секунду (1000мс)

java.util.Timer uTimer1 = new java.util.Timer();

uTimer1.schedule(new java.util.TimerTask() {

public void run() {

jLabel3.setText(new java.text.SimpleDateFormat(

"dd-MMM-yy hh:mm:ss").format(java.util.Calendar.getInstance().getTime()));

} }, 0, 1000);

} // ----------- Конец конструктора формы

2. РАБОТА СО ЗВУКОМ

2.1. Проигрывание звукового wav-файла из jar-ресурса

private void jButton2ActionPerformed(java.awt.event.ActionEvent evt) {

// Издаем звук файла "snd.wav" из jar-ресурса программы

try {

Clip c = AudioSystem.getClip(); // Подключение к звуковой системе

URL url = this.getClass().getResource("snd.wav"); // Находим звук в jar-ресурсе

// Подключение к звуковому файлу

AudioInputStream ais = AudioSystem.getAudioInputStream(url);

c.open(ais); // Проиграть звук

c.loop(0); // Проиграть звук один раз, без повторов

// Если необходимо гарантированное время для проигрывания, то нужен следующий код:

//            try { Thread.sleep(500); // Время ожидания программы пока играет звук, мс

//             } catch (InterruptedException ex) {

//             }

} catch (LineUnavailableException | UnsupportedAudioFileException | IOException ex) {

ex.printStackTrace();

}

}

3. РАБОТА С ГРАФИКОЙ

В Java имеется возможность наносить собственный рисунок на визуальные элементы программы, в частности на панели JPanel. Это позволяет создавать визуальные графики, делать графическую анимацию и многое другое.

Для того чтобы панель  JPanel позволила наносить на нее рисунок, она должна быть создана не из ее родного класса javax.swing.JPanel, а через новый дочерний класс, который является потомком для javax.swing.JPanel и имеет переопределенный метод рисования «paint».

Для того чтобы сделать обычную панель JPanel на форме в пригодную для рисования, нужно правой кнопкой мыши вызвать на ней контекстное меню и выбрать пункт «Настроить код»:

Описание: C:\Documents and Settings\User\Рабочий стол\eps\src\eps\doc\lectures\Работа с таймерами, звуком, графикой, треем, потоками, реестром.files\image001.jpg

В редакторе заказного кода необходимо в коде инициализации изменить значение «код по умолчанию» на значение «пользовательское создание» и изменить строчку «jPanel1 = new javax.swing.JPanel();» на значение «jPanel1 = new MyPicture();»:

Описание: C:\Documents and Settings\User\Рабочий стол\eps\src\eps\doc\lectures\Работа с таймерами, звуком, графикой, треем, потоками, реестром.files\image002.jpg

Мы указали, что панель формы jPanel1 будет создана не как обычно, а на основе нашего собственного класса, который мы назвали «MyPicture». Класс «MyPicture» нужно вписать в код программы, как например, показано далее в примере.

3.1. Пример рисования на панели JPanel с заливкой и буфером изображения

public class NewJFrame extends javax.swing.JFrame {

public class MyPicture extends JPanel { // КЛАСС РИСОВАНИЯ СВОЕЙ КАРТИНКИ

Graphics2D canvas;   // Класс рисования

BufferedImage buff;  // Буферное изображение

int x = 400; // Константа размера полотна по х

int y = 250; // Константа размера полотна по y

MyPicture() {

// Создаем буферное полотно для рисования размером x-y

buff = new BufferedImage(x, y, BufferedImage.TYPE_INT_RGB);

// Создаем двустороннюю связь между буферным изображением и классом рисования

canvas = (Graphics2D) buff.getGraphics();

canvas.setPaint(Color.GRAY); // Устанавливаем цвет рисования серым

canvas.fillRect(0, 0, x, y); // Заливаем полотно для рисования

canvas.setPaint(Color.BLACK);  // Устанавливаем цвет рисования черным

canvas.drawOval(100, 80, 90, 90);  // Отрисовываем большой овал

canvas.drawArc(100, 115, 90, 30, 180, 180); // Отрисовываем дугу по середине овала

//рисуем два мелньких круга сверху и снизу

canvas.drawOval(140, 70, 10, 10);

canvas.drawOval(140, 170, 10, 10);

//устанавливаем стиль и пишим текст

canvas.setFont(new Font("Tahoma", Font.BOLD | Font.ITALIC, 40));

canvas.drawString("Java!", 85, 50);

try {

// При помощи созданной функции заливки закрашиваем две части главного овала

// и два маленьких кружка

fill(110, 110, Color.GRAY, Color.WHITE);

fill(140, 150, Color.GRAY, Color.RED);

fill(145, 75, Color.GRAY, Color.RED);

fill(145, 175, Color.GRAY, Color.WHITE);

} catch (Exception ex) {

}

}

@Override

public void paintComponent(Graphics g) {

super.paintComponent(g); // Отрисовываем панель и компоненты на ней

g.drawImage(buff, 0, 0, this); // Отрисовываем буфер с нашим изображением на панель

}

private void fill(int x, int y, Color bgcolor, Color color) throws Exception {

// Заливка фигур методом ромба, параметры: х,y- координаты начала заливки,

// bgcolor-цвет который надо закрашивать, color-цвет которым надо закрашивать

ArrayList<Point> point = new ArrayList<>(); // Создаем динамический массив точек

point.add(new Point(x, y)); // Добавляем начальную точку в массив

Color oldColor = canvas.getColor(); // Сохраняем старый цвет рисования

canvas.setPaint(color); //ставим цвет закраски

while (point.size() > 0) { // Пока в массиве имеются точки для закрашивания

Point p = point.remove(0); // Считываем координаты первой точки, и удаляем ее из массива

x = p.x; y = p.y;

if (bgcolor.getRGB() == buff.getRGB(x, y)) { // Если ее надо нам закрасить

canvas.drawLine(x, y, x, y); // Закрашиваем точку

point.add(new Point(x + 1, y)); // Добавляем точку справа

point.add(new Point(x - 1, y)); // Добавляем точку слева

point.add(new Point(x, y + 1)); // Добавляем точку снизу

point.add(new Point(x, y - 1)); // Добавляем точку сверху

}

}

canvas.setPaint(oldColor); //ставим старый цвет рисования

repaint();  // Перерисовываем изображение

}

}

public NewJFrame () {

initComponents();

}

Описание: C:\Documents and Settings\User\Рабочий стол\eps\src\eps\doc\lectures\Работа с таймерами, звуком, графикой, треем, потоками, реестром.files\image003.jpg

3.2. Пример простого рисования на панели JPanel

public class NewJFrame extends javax.swing.JFrame {

// Делаем общедоступные переменные-массивы для использования в панели рисования и для всех других компонент программы

char[] mas = {'T', 'S', 'E', 'R', 'G', '!'};

int[] xArray = {20, 40, 60, 80, 100, 120, 130, 140, 280, 332};

int[] yArray = {350, 345, 340, 310, 290, 280, 275, 273, 271, 269};

public class MyPicture extends JPanel { // КЛАСС РИСОВАНИЯ СВОЕЙ КАРТИНКИ

@Override

public void paintComponent(Graphics g) { // Переменная «g» служит для доступа к классическому Java-рисованию

super.paintComponent(g); // // Отрисовываем панель и компоненты на ней

Graphics2D g2 = (Graphics2D) g; // Получаем переменную «g2 доступа к Java2D-рисованию

jLabel1.setText("Рисуем!!!"); // Выводим в метку текст (доступ к внешнему компоненту)

this.setBackground(new Color(153,255,153)); // Установка цвета фона панели

this.setForeground(Color.darkGray); // Установка цвета рисования на панели

int w = getWidth(); int h = getHeight(); // Узнать ширину и высоту области рисования

// Создаем объект-градиент

GradientPaint gradient = new GradientPaint(0, 0,Color.orange, w, h, Color.green, true);

g2.setPaint(gradient); // Установить вид закраски

g2.fillRect(0, 0, w, h); // Нарисовать закрашенный градиентной заливкой четырехугольник

g.drawLine(110, 120, 110, 120); // Рисование точки

g.drawLine(20, 20, 360, 20); // Рисование линии

Color oldColor = g.getColor(); // Считать текущий цвет "foreground"

Color newColor = new Color(0, 0, 255); // Создать переменную с цветом

g.setColor(newColor); // Установка нового цвета для текущего цвета

g.drawLine(20, 30, 360, 30); // Рисование линии

g.setColor(oldColor); // Установка старого текущего цвета

g.drawRect(20, 40, 340, 20); // Рисование не закрашенного четырехугольника

newColor = new Color(100, 15, 255); // Создать переменную с цветом

g.setColor(newColor); // Установка нового текущего цвета

g.fillRect(80, 80, 50, 15); // Рисование закрашенного четырехугольника

g.setColor(oldColor); // Установка старого текущего цвета

// Рисование не закрашенного округлого четырехугольника

g.drawRoundRect(20, 70, 340, 30, 20, 15);

g.drawOval(20, 110, 150, 60); // Нарисовать овал

g.drawOval(200, 110, 60, 60); // Нарисовать круг

g.drawArc(280, 110, 80, 60, 0, 180); // Нарисовать дугу

int[] arrayX = {20, 100, 100, 250, 250, 20, 20, 50}; // Координаты x полигона

int[] arrayY = {180, 180, 200, 200, 220, 200, 200, 190}; // Координаты y полигона

Polygon poly = new Polygon(arrayX, arrayY, 8); // Объект-полигон

g.drawPolygon(poly); // Нарисовать объект-полигон

Point aPoint = new Point(50, 190); // Получить объект-точку

if (poly.contains(aPoint)) { // Если точка имеется в полигоне, то

g.drawString("Yes", 50, 190); // Нарисовать текст текущим цветом "Yes"

}

g.setColor(new Color(10, 200, 55)); // Установить новый цвет

g.fillArc(50, 70, 30, 40, 50, 190); // Нарисовать закрашенный сектор

newColor = new Color(10, 10, 155); // Создать переменную с цветом

g.setColor(newColor); // Установка нового текущего цвета

Font font = new Font("Tahoma", Font.BOLD | Font.ITALIC, 40); // Задать объект-шрифт

Font oldFont = g.getFont(); // Считать текущий шрифт (фонт)

g.setFont(font); // Установить собственный тип шрифта

g.drawString("TSN", 270, 220); // Нарисовать текст "TSN"

g.setFont(oldFont); // Установить старый (сохраненный) тип шрифта

g.setColor(oldColor); // Установка нового текущего цвета

// Нарисовать оси графика

g.drawLine(20, 220, 20, 350); g.drawLine(20, 350, 360, 350);

g.drawString("Y", 25, 230);   g.drawString("X", 350, 346);

// Нарисовать график

g.setColor(newColor); // Установить собственный тип шрифта

g.drawPolyline(xArray, yArray, 10); // Нарисовать объект-полигон

g.setColor(oldColor); // Установка нового текущего цвета

g.drawString("y = f(x)", 180, 267); // Нарисовать текст "y = f(x)"

// Рисование символов на экране

g2.drawChars(mas, 0, 6, 123, 321);

// Использование перьев в Graphics2D

BasicStroke penl = new BasicStroke(10, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10);

g2.setStroke(penl);

g2.draw(new Rectangle2D.Double(350, 50, 50, 50));

}

}

public NewJFrame() {

initComponents();

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {

// Изменяем данные картинки

mas[0] = 'x'; // Меняем символ «T» в надписи «TSERG!», получится «xSERG

xArray[0] = 10; yArray[0] = 200; // Меняем координаты для графика рисунка

this.repaint(); // Перерисовать все компоненты формы

}

Вот что получится в результате выполнения программы:

Описание: C:\Documents and Settings\User\Рабочий стол\eps\src\eps\doc\lectures\Работа с таймерами, звуком, графикой, треем, потоками, реестром.files\image004.jpg

4. РАБОТА С ТРЕЕМ

Для того чтобы программа могла сворачиваться в системный трей, необходимо модифицировать  главную форму программы. Наиболее простой способ состоит в создании в программе нового дополнительного класса работы с треем, и привязке к нему основной формы программы:

1)       Заменяем к коде у формы строку «public class NewJFrame extends javax.swing.JFrame на значение «public class NewJFrame extends TrayForm {».

2)       Добавляем в программу новый класс «TrayForm»:

Описание: C:\Documents and Settings\User\Рабочий стол\eps\src\eps\doc\lectures\Работа с таймерами, звуком, графикой, треем, потоками, реестром.files\image006.jpg

Описание: C:\Documents and Settings\User\Рабочий стол\eps\src\eps\doc\lectures\Работа с таймерами, звуком, графикой, треем, потоками, реестром.files\image007.jpg

3)       Вписываем следующий код в созданный класс «TrayForm»:

package tsn_jedoc_2013;

import java.awt.AWTException;

import java.awt.Image;

import java.awt.MenuItem;

import java.awt.PopupMenu;

import java.awt.SystemTray;

import java.awt.Toolkit;

import java.awt.TrayIcon;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.awt.event.WindowEvent;

import java.awt.event.WindowStateListener;

import java.net.URL;

import javax.swing.JFrame;

public class TrayForm extends JFrame {

private SystemTray systemTray = SystemTray.getSystemTray();

private TrayIcon trayIcon;

public  TrayForm() {

super();

URL resource = getClass().getResource("icon.png"); // Имя картинки для трея (из JAR-ресурса)

Image image = Toolkit.getDefaultToolkit().getImage(resource);

// Надпись в трее при наведении курсора на значок программы

trayIcon = new TrayIcon(image, "Программирование на Java (Swing)");

trayIcon.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) { // Восстановление программы из иконки

setVisible(true); setState(JFrame.NORMAL); removeTrayIcon();

} });

addWindowStateListener(new WindowStateListener() {

public void windowStateChanged(WindowEvent e) { // Сворачивание программы в иконку

if (e.getNewState() == JFrame.ICONIFIED) {

setVisible(false); addTrayIcon();

}  } });

PopupMenu popupMenu = new PopupMenu(); // Создание меню для трея

MenuItem item1 = new MenuItem("Развернуть программу");

MenuItem item2 = new MenuItem("Выход");

item1.addActionListener(new ActionListener() { // Команды контекстного меню трея

public void actionPerformed(ActionEvent e) { // Восстановление программы из иконки

setVisible(true); setState(JFrame.NORMAL); removeTrayIcon();

} });

item2.addActionListener(new ActionListener() {

public void actionPerformed(ActionEvent e) { // Выход из программы

dispose(); System.exit(0);

} });

// Установка меню для трея

popupMenu.add(item1); popupMenu.add(item2); trayIcon.setPopupMenu(popupMenu);

}

private void removeTrayIcon() { systemTray.remove(trayIcon); }

private void addTrayIcon() {

try {

systemTray.add(trayIcon);

trayIcon.displayMessage("Программирование на Java (Swing)",

"Приложение свернуто. Двойной клик для восстановления окна", TrayIcon.MessageType.INFO);

} catch (AWTException ex) {

ex.printStackTrace();

}

}

}

5. РАБОТА С ПОТОКАМИ

Практически все операционные системы поддерживают концепцию процессов - независимо работающих программ, до некоторой степени изолированных друг от друга. Потоками называются средства, позволяющие нескольким операциям сосуществовать в рамках одного процесса. Потоки представляют собой независимые параллельные пути исполнения программ.

Потоки используют в программах для того чтобы:

-          повысить отзывчивость интерфейса пользователя;

-          использовать преимущества многопроцессорных систем;

-          упростить моделирование;

-          выполнять асинхронную или фоновую обработку данных.

5.1. Пример работы с потоком в программе с графическим интерфейсом

public class Form1 extends javax.swing.JFrame {

public class Form1 extends javax.swing.JFrame {

// Текст потока прописывается в данном месте кода формы вручную

class TThread1 extends Thread { // ПРИМЕР ПОТОКА

public void run() { // ГЛАВНЫЙ МЕТОД ПОТОКА

try { while (true) { // Выполняем поток постоянно до прерывания

jLabel2.setText(String.valueOf(Math.random()));

if (Math.random()>0.999) break; // Случайное само прерывание потока

sleep(1); // Задержка потока для анализа прерывания

} } catch (InterruptedException e) { // Прерывание потока

jLabel2.setText("Поток принудительно остановлен!!!");

return; // Выход из потока

} jLabel2.setText("Поток остановился");

}

} Thread tThread1; // Переменная для доступа к потоку

private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {

// Создание и запуск потока

tThread1 = new TThread1(); tThread1.start();

}

private void jButton4ActionPerformed(java.awt.event.ActionEvent evt) {

// Принудительная остановка потока

tThread1.interrupt();

}

6. РАБОТА С СИСТЕМНЫМ РЕЕСТРОМ

Системный реестр – это иерархическая централизованная база данных в операционных системах. В реестре хранятся данные, необходимы для правильного функционирования ОС: профили всех пользователей, сведения об установленном программном обеспечении и типах документов, которые могут быть созданы каждой программой, информация о свойствах папок и значках приложений, а также установленном оборудовании и используемых портах.

6.1. Пример работы с системным реестром в консольном приложении

package tsn01.pref;

import java.util.prefs.Preferences;

import java.util.Arrays;

public class App1 {

public static void main(String[] args) {

// РАБОТА С РЕЕСТРОМ WINDOWS

// Создается (открывается ) раздел в реестре:

// HKEY_CURRENT_USER\Software\JavaSoft\Prefs\tsn_demo и вложенный узел "person"

// Для Linux: $HOME/.java/.userPrefs/.tsn_demo

Preferences node = Preferences.userRoot().node("tsn_demo");

Preferences node2 = Preferences.userRoot().node("tsn_demo").node("person");

// Создается раздел в реестре: HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Prefs\tsn_demo

// и вложенный узел «"person"»

// Preferences node = Preferences.systemRoot().node("tsn_demo");

// Preferences node2 = Preferences.systemRoot().node("tsn_demo").node("person");

byte k[] = new byte[]{1, 2, 3, 4, 5, 6, 7, 8}; // Массив байт

// Запись данных в реестр

node.put("fio", "Talipov Sergey N."); // Записать (обновить) строковый параметр "fio"

node.putInt("age", 38); // Записать (обновить) целый параметр "age"

node2.putFloat("weight", 70.51f);  // Записать (обновить) вещественный параметр "weight"

node2.putBoolean("men", true);  // Записать (обновить) логический параметр "men"

node2.putByteArray("num", k);  // Записать (обновить) массив байт "num"

// Считывание данных из реестра

String s = node.get("fio", "???"); // Считать строковый параметр "fio"

int n = node.getInt("age", 0); // Считать целый параметр "age"

float f = node2.getFloat("weight", 0); // Считать вещественный параметр "weight"

boolean b = node2.getBoolean("men", true); // Считать логический параметр "men"

byte[] kk = node2.getByteArray("num", null); // Считать массив байт "num"

String s2 = Arrays.toString(kk); // Преобразовать массив байт в строку

// Вывод данных на экран

System.out.println(s + " - " + n); // Выведется на экран "Talipov Sergey N. - 38"

System.out.println(f + " - " + b); // Выведется на экран "70.51 - true"

System.out.println(s2); // Выведется на экран "[1, 2, 3, 4, 5, 6, 7, 8]"

}

}

Записанные значения в реестре «HKEY_CURRENT_USER\Software\JavaSoft\Prefs\tsn_demo»:

Описание: C:\Documents and Settings\User\Рабочий стол\eps\src\eps\doc\lectures\Работа с таймерами, звуком, графикой, треем, потоками, реестром.files\image008.jpg

Записанные значения в реестре «HKEY_CURRENT_USER\Software\JavaSoft\Prefs\tsn_demo\person»:

Описание: C:\Documents and Settings\User\Рабочий стол\eps\src\eps\doc\lectures\Работа с таймерами, звуком, графикой, треем, потоками, реестром.files\image009.jpg